/*
* "PS2" Application Framework
*
* University of Abertay Dundee
* May be used for educational purposed only
*
* Author - Dr Henry S Fortuna
*
* $Revision: 1.4 $
* $Date: 2007/08/27 20:22:34 $
*
*/

#ifndef __PS2VECTOR4_H__
#define __PS2VECTOR4_H__

#include <stdio.h>
#include "ps2maths.h"

class Vector4 {
public:
    // Constructors
    Vector4(void);
    Vector4(const float _x, const float _y, const float _z, const float _w);
    // Copy constructor - use as Vector4 V1 = V;
    Vector4(const Vector4 & rhs);

    ~Vector4(void);

    // Operations with other vectors
    Vector4 & operator+=(const Vector4 & rhs);
    Vector4 & operator-=(const Vector4 & rhs);

    // Special arithmetic
    float Dot3(const Vector4 & rhs) const;
    float Dot4(const Vector4 & rhs) const;
    Vector4 Cross(const Vector4 & rhs) const;

    Vector4 & operator*=(const float s);
    Vector4 & operator/=(const float s);

    bool operator==(const Vector4 & rhs) const;

    // Miscellaneous
    inline float Length(void) const;
    float LengthSqr(void) const;
    Vector4 Normalise(void);
    void NormaliseSelf(void);
    void DumpVector4(char * s = NULL);
    int IsZeroVector(void);

    // Member data
    float x,y,z,w;
};

inline Vector4 operator + (const Vector4 &v1,
                           const Vector4 &v2) {
    return Vector4(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, 1.0f);
}

inline Vector4 operator - (const Vector4 &v1,
                           const Vector4 &v2) {
    return Vector4(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, 1.0f);
}

inline Vector4 operator - (const Vector4 &v1) {
    return Vector4(-v1.x, -v1.y, -v1.z, 1.0f);
}

inline Vector4 operator * (const Vector4 &v,
                           const float &s) {
    return Vector4(v.x * s, v.y * s, v.z * s, 1.0f);
}

inline Vector4 operator * (const float & s,
                           const Vector4 &v) {
    return Vector4(v.x * s, v.y * s, v.z * s, 1.0f);
}

inline Vector4 operator / (const Vector4 &v,
                           const float & s) {
    return Vector4(v.x / s, v.y / s, v.z / s, 1.0f);
}

inline Vector4 CrossProduct (const Vector4 &v1,
                             const Vector4 &v2) {
    return Vector4(v1.y * v2.z - v1.z * v2.y,
                   v1.z * v2.x - v1.x * v2.z,
                   v1.x * v2.y - v1.y * v2.x,
                   1.0f);
}

inline float DotProduct4(const Vector4 &v1,
                         const Vector4 &v2) {
    return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w);
}

inline float DotProduct3(const Vector4 &v1,
                         const Vector4 &v2) {
    return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
}

// Return the ZeroVector if the lenth of the vector is very small
inline Vector4 Normalise (const Vector4 &v) {
    float tmp_Length;
    Vector4 ZeroVector = Vector4(0.0f, 0.0f, 0.0f, 0.0f);

    tmp_Length = v.Length();

    if (tmp_Length < 0.0001f)
        return ZeroVector;
    else
        return (v / tmp_Length);
}

inline float Vector4::Length() const {
    return Sqrt(x * x + y * y + z * z);
}

#endif
